package dao

import (
	"fmt"
	"math/rand"
	"net/http"
	"path"
	"strconv"
	"strings"
	"time"
	"user_srv/basic/config"
	user "user_srv/basic/proto"
	"user_srv/handler/model"
	pg "user_srv/pkg"
	un "user_srv/untils"

	"github.com/Addiction-fei/public/pkg"
	"github.com/Addiction-fei/public/untils"
	"github.com/google/uuid"
)

// 发送短信
func SendSms(in *user.SendSmsReq) error {
	count := config.Rdb.Get(config.Ctx, "SendSmsErr"+in.Phone).Val()
	if count == "3" {
		return fmt.Errorf("发送短信次数超3次，请一分钟后再试")
	}
	if !untils.IsValidMobile(in.Phone) {
		return fmt.Errorf("手机格式错误")
	}

	code := rand.Intn(9000) + 1000
	sms, err := pkg.SendSms(config.SignName, config.TemplateCode, in.Phone, strconv.Itoa(code))
	if err != nil {
		return fmt.Errorf("发送短信失败: %s", err.Error())
	}
	if *sms.Body.Code != "OK" {
		return fmt.Errorf("发送短信失败: %s", *sms.Body.Message)
	}
	config.Rdb.Set(config.Ctx, "SendSms"+in.Phone, code, time.Minute)
	config.Rdb.Incr(config.Ctx, "SendSmsErr"+in.Phone)
	config.Rdb.Expire(config.Ctx, "SendSmsErr"+in.Phone, time.Minute)
	return nil
}

// 用户注册
func Register(in *user.RegisterReq) (*model.User, error) {
	var users model.User
	if !untils.IsValidMobile(in.Phone) {
		return nil, fmt.Errorf("手机格式错误")
	}
	users.Phone = in.Phone
	users.Password = pkg.DoubleMd5(in.Password)
	if err := users.GetUserInfo(&model.User{Phone: in.Phone}); err != nil {
		return nil, fmt.Errorf("查询用户信息失败")
	}
	if users.Id != 0 {
		return nil, fmt.Errorf("该用户已存在")
	}
	if err := users.Register(); err != nil {
		return nil, fmt.Errorf("注册用户失败")
	}
	return &users, nil
}

// QQ本地模拟登录
func QQLogin(in *user.QQLoginReq) (*model.User, error) {
	uidStr, err := un.MockToken(in.Code)
	if err != nil {
		return nil, fmt.Errorf("获取token失败")
	}
	uid, _ := strconv.Atoi(uidStr)
	var u model.User
	if err = u.GetUserInfo(&model.User{Id: uint(uid)}); err == nil && u.Id > 0 {

		nick, avatar, err := un.MockUserInfo(uidStr)
		if err != nil {
			return nil, fmt.Errorf("获取用户信息失败:%s", err.Error())
		}
		u.Nickname = nick
		u.Avatar = avatar
		u.LastLoginTime = time.Now()
		u.LoginType = 3
		if err = u.UpdateUserInfo(&model.User{Id: u.Id}); err != nil {
			return nil, fmt.Errorf("更新用户失败", err.Error())
		}
		return &u, nil
	}
	nick, avatar, _ := un.MockUserInfo(uidStr)
	u = model.User{
		Id:        uint(uid),
		QqOpenid:  un.MockOpenid(uidStr),
		Nickname:  nick,
		Avatar:    avatar,
		LoginType: 3,
	}

	if err = u.Register(); err != nil {
		return nil, fmt.Errorf("插入用户信息失败")
	}

	return &u, nil

}

// 修改用户信息或者是完善-带生日修改限制
func UpdateUserInfo(in *user.UpdateUserInfoReq) (*model.User, error) {
	Birthday, err := time.ParseInLocation(time.DateTime, in.Birthday, time.Local)
	if err != nil {
		return nil, fmt.Errorf("生日格式填写错误")
	}
	Birthday = Birthday.Truncate(24 * time.Hour)

	var oldUser model.User
	if err = oldUser.GetUserInfo(&model.User{Id: uint(in.Id)}); err != nil {
		return nil, fmt.Errorf("获取用户信息失败")
	}
	if oldUser.Id == 0 {
		return nil, fmt.Errorf("该用户不存在无法修改")
	}

	birthdayKey := fmt.Sprintf("user:%d:birthday_modified", in.Id)

	if !oldUser.Birthday.Equal(Birthday) {
		count, _ := config.Rdb.Get(config.Ctx, birthdayKey).Int()
		if count > 0 {
			return nil, fmt.Errorf("抱歉，生日一年内只能修改一次")
		}
	}
	users := &model.User{
		Nickname:  in.Nickname,
		Avatar:    in.Avatar,
		Gender:    uint(in.Gender),
		Birthday:  Birthday,
		Region:    in.Region,
		Signature: in.Signature,
	}
	users.Id = uint(in.Id)
	if err = users.UpdateUserInfo(&model.User{Id: uint(in.Id)}); err != nil {
		return nil, fmt.Errorf("更新用户信息失败")
	}
	//如果生日被修改，记录修改时间到redis
	if !oldUser.Birthday.Equal(Birthday) {
		config.Rdb.Set(config.Ctx, birthdayKey, 1, 365*24*time.Hour)
	}
	return users, nil
}

// 用户上传图片
func UpLoadPhoto(in *user.UpLoadPhotoReq) (*model.UserPhotos, error) {
	var users model.User
	if err := users.GetUserInfo(&model.User{Id: uint(in.UserId)}); err != nil {
		return nil, fmt.Errorf("获取用户信息失败")
	}
	if users.AccountStatus != 1 || users.Id == 0 {
		return nil, fmt.Errorf("账号不存在或异常上传失败")
	}
	//防刷
	today := time.Now().Format("20060102")
	key := fmt.Sprintf("up:%d:%s", in.UserId, today)
	result, _ := config.Rdb.Incr(config.Ctx, key).Result()
	if result == 1 {
		config.Rdb.Expire(config.Ctx, key, 24*time.Hour)
	}
	maxs := int64(1)
	if users.IsVip == 1 {
		maxs = 3
	}
	if result > maxs {
		return nil, fmt.Errorf("抱歉您今日上传已达上限")
	}
	head, err := http.Head(in.ImageUrl)
	if err != nil {
		return nil, fmt.Errorf("无法获取图片大小，请检查地址")
	}

	size := int(head.ContentLength)
	if size > 2*1024*1024 {
		return nil, fmt.Errorf("请上传小于2MB图片")
	}

	ext := strings.ToLower(path.Ext(in.ImageUrl))
	if ext != ".jpg" && ext != ".png" && ext != ".jpeg" {
		return nil, fmt.Errorf("图片格式必须是.jpg、.png、.jpeg")
	}
	userPhoto := model.UserPhotos{
		UserId:   uint(in.UserId),
		ImageUrl: in.ImageUrl,
	}
	if err = userPhoto.UploadPhoto(); err != nil {
		return nil, fmt.Errorf("上传失败")
	}
	return &userPhoto, nil

}

// 用户购买会员套餐
func ByVipPlan(in *user.BuyVipPlanReq) (*model.UserVip, error) {
	// 验证会员套餐是否存在
	var vipPlan model.VipPlans
	if err := vipPlan.GetVipInfo(&model.VipPlans{Id: uint(in.PlanId), IsAvailable: 1}); err != nil {
		return nil, fmt.Errorf("该会员套餐不存在或已删除")
	}

	// 检查用户是否已有有效会员
	var existingVip model.UserVip
	if err := existingVip.GetUserActiveVip(&model.UserVip{UserId: uint(in.UserId), IsActive: 1}); err == nil {
		if existingVip.EndTime.After(time.Now()) {
			return nil, fmt.Errorf("用户已购买会员套餐，有效期至：%s", existingVip.EndTime.Format("2006-01-02"))
		}
	}

	// 计算会员开始和结束时间
	startTime := time.Now()
	endTime := startTime.AddDate(0, 0, int(vipPlan.PlanDays))

	// 如果用户已有会员记录且未过期，续费处理
	if existingVip.Id > 0 && existingVip.EndTime.After(time.Now()) {
		// 续费在原有结束时间上增加
		endTime = existingVip.EndTime.AddDate(0, 0, int(vipPlan.PlanDays))

		// 禁用旧的会员记录
		existingVip.IsActive = 0
		if err := existingVip.UpdateUserVipStatus(&model.UserVip{Id: existingVip.Id}); err != nil {
			return nil, fmt.Errorf("禁用用户会员记录失败")
		}
	}

	// 创建新的会员记录
	userVip := model.UserVip{
		UserId:    uint(in.UserId),
		PlanId:    uint(in.PlanId),
		OrderId:   1,
		StartTime: startTime,
		EndTime:   endTime,
		IsActive:  1,
	}

	if err := userVip.CreateUserVip(); err != nil {
		return nil, fmt.Errorf("创建会员订单失败")
	}

	// 修改用户表会员状态
	var users model.User
	users.IsVip = 1
	users.VipExpireTime = endTime // 同时更新过期时间
	if err := users.UpdateUserInfo(&model.User{Id: uint(in.UserId)}); err != nil {
		return nil, fmt.Errorf("更新用户会员状态失败")
	}

	return &userVip, nil
}

// 用户查看会员套餐列表
func GetVipPlansList(in *user.GetVipPlansReq) ([]*user.VipPlan, error) {
	var vipPlans model.VipPlans
	list, err := vipPlans.GetVipList()
	if err != nil {
		return nil, fmt.Errorf("获取会员套餐列表失败")
	}
	var VipPlansList []*user.VipPlan
	for _, plans := range list {
		VipPlansList = append(VipPlansList, &user.VipPlan{
			Id:          int64(plans.Id),
			PlanName:    plans.PlanName,
			PlanDays:    int64(plans.PlanDays),
			Price:       plans.Price,
			Description: plans.Description,
		})
	}
	return VipPlansList, err
}

// 用户查看会员套餐详情
func GetVipPlansDetail(in *user.GetUserVipInfoReq) (*model.UserVipDetail, error) {
	userVip := &model.UserVip{}
	where := model.UserVip{UserId: uint(in.UserId), IsActive: 1}
	detail, err := userVip.GetUserVipDetail(&where)
	if err != nil {
		return nil, fmt.Errorf("获取用户会员详情失败")
	}
	if detail.Id == 0 {
		return nil, fmt.Errorf("该用户未购买会员套餐")
	}
	//检查用户是否有效会员
	if detail.EndTime.Before(time.Now()) {
		//更新状态为过期
		updateWhere := &model.UserVip{Id: detail.Id}
		userVip.IsActive = 0
		if err = userVip.UpdateUserVipStatus(updateWhere); err != nil {
			return nil, fmt.Errorf("更新会员状态失败")
		}
		return nil, fmt.Errorf("用户会员已过期")
	}
	return detail, nil

}

// 购买虚拟商品
func BuyVirtualGoods(in *user.BuyVirtualGoodsReq) (*user.BuyVirtualGoodsResp, error) {
	//验证虚拟商品是否存在
	var goods model.VirtualGoods
	if err := goods.GetGoodsInfo(&model.VirtualGoods{Id: uint(in.GoodsId)}); err != nil {
		return nil, fmt.Errorf("该虚拟商品不存在或已删除")
	}
	if goods.Id == 0 {
		return nil, fmt.Errorf("该虚拟商品不存在")
	}
	//验证库存
	if goods.StockQuantity != -1 && goods.StockQuantity < int(in.Quantity) {
		return nil, fmt.Errorf("商品库存不足")
	}
	//获取用户钱包信息
	var wallet model.UserWallet
	if err := wallet.GetUserWallet(&model.UserWallet{Id: uint(in.UserId)}); err != nil {
		return nil, fmt.Errorf("获取用户钱包失败")
	}
	//计算总价并验证余额
	totalPrice := goods.Price * float64(in.Quantity)

	//根据货币类型检查余额
	switch goods.CurrencyType {
	case 1: //金币
		if wallet.GoldCoins < uint(totalPrice) {
			return nil, fmt.Errorf("金币不足，需要%.2f,当前余额%d", totalPrice, wallet.GoldCoins)
		}
	case 2: //钻石
		if wallet.Diamonds < uint(totalPrice) {
			return nil, fmt.Errorf("钻石不足，需要%.2f,当前余额%d", totalPrice, wallet.Diamonds)
		}
	case 3: //积分
		if wallet.Points < uint(totalPrice) {
			return nil, fmt.Errorf("积分不足，需要%.2f,当前余额%d", totalPrice, wallet.Points)
		}
	default:
		return nil, fmt.Errorf("不支持的货币类型")
	}
	order := model.VirtualGoodsOrder{
		OrderSn:      uuid.NewString(),
		UserId:       uint(in.UserId),
		GoodsId:      uint(in.GoodsId),
		Quantity:     uint(in.Quantity),
		TotalPrice:   totalPrice,
		CurrencyType: goods.CurrencyType,
	}
	if err := order.CreateOrder(); err != nil {
		return nil, fmt.Errorf("创建订单失败")
	}
	//扣款
	if err := deductBalance(uint(in.UserId), goods.CurrencyType, totalPrice); err != nil {
		//如果扣款失败，更新订单状态为支付失败
		order.Status = 3
		order.UpdateOrder(&model.VirtualGoodsOrder{Id: order.Id})
		return nil, fmt.Errorf("支付失败:%v", err)
	}
	//扣减库存（如果不是无限库存）
	if goods.StockQuantity != 1 {
		if err := updateGoodsStock(uint(in.GoodsId), uint(in.Quantity)); err != nil {
			return nil, fmt.Errorf("库存扣减失败")
		}
	}

	//添加商品到用户背包
	if err := addToUserInventory(uint(in.UserId), uint(in.GoodsId), int(in.Quantity), int(goods.DurationDays)); err != nil {
		return nil, fmt.Errorf("添加商品到背包失败", err.Error())
	}

	//获取新的余额
	var newBalance float64
	switch goods.CurrencyType {
	case 1: //金币
		newBalance = float64(wallet.GoldCoins - uint(totalPrice))
	case 2: //钻石
		newBalance = float64(wallet.Diamonds - uint(totalPrice))
	case 3: //积分
		newBalance = float64(wallet.Points - uint(totalPrice))

	}

	//生成支付链接
	payUrl := pg.AliPay(order.OrderSn, fmt.Sprintf("%.2f", totalPrice))
	return &user.BuyVirtualGoodsResp{
		OrderSn:    order.OrderSn,
		Message:    payUrl,
		NewBalance: newBalance,
	}, nil

}

// 扣减余额
func deductBalance(userId uint, currencyType uint, amount float64) error {
	var wallet model.UserWallet
	if err := wallet.GetUserWallet(&model.UserWallet{UserId: userId}); err != nil {
		return err
	}
	switch currencyType {
	case 1: //金币
		wallet.GoldCoins -= uint(amount)
	case 2: //钻石
		wallet.Diamonds -= uint(amount)

	case 3: //积分
		wallet.Points -= uint(amount)
	default:
		return fmt.Errorf("不支持的货币类型")
	}
	//更新总消费
	wallet.TotalSpent += amount
	return wallet.UpdateUserWallet(&model.UserWallet{UserId: userId})

}

// 更新商品库存
func updateGoodsStock(goodsId uint, quantity uint) error {
	var goods model.VirtualGoods
	if err := goods.GetGoodsInfo(&model.VirtualGoods{Id: goodsId}); err != nil {
		return err
	}
	goods.StockQuantity -= int(quantity)
	return goods.UpdateVirtualGoods(&model.VirtualGoods{Id: goodsId})
}

// 添加商品到用户背包
func addToUserInventory(userId, goodsId uint, quantity int, durationDays int) error {
	var expireTime time.Time

	//计算过期时间
	if durationDays > 0 {
		expireTime = time.Now().AddDate(0, 0, durationDays)
	}
	//检查是否已存在相同的未使用的商品
	var existringInventory model.UserInventory
	err := existringInventory.GetUserInventory(&model.UserInventory{
		UserId:  userId,
		GoodsId: goodsId,
		Status:  1, //未使用
	})
	if err == nil && existringInventory.Id > 0 {
		//如果已存在，增加数量
		newQUantiry := existringInventory.Quantity + quantity
		return existringInventory.UpdateInventory(&model.UserInventory{
			Id:       existringInventory.Id,
			Quantity: newQUantiry,
		})
	}
	//如果不存在，创建新的背包记录
	inventory := model.UserInventory{
		UserId:     userId,
		GoodsId:    goodsId,
		Quantity:   quantity,
		Status:     1,
		ExpireTime: expireTime,
	}
	return inventory.CreateInventory()

}

// 获取用户钱包信息
func GetUserWallet(in *user.GetUserWalletReq) (*model.UserWallet, error) {
	var wallet model.UserWallet
	if err := wallet.GetUserWallet(&model.UserWallet{UserId: uint(in.UserId)}); err != nil {
		return nil, fmt.Errorf("获取用户信息失败")
	}
	if wallet.Id == 0 {
		return nil, fmt.Errorf("用户为创建钱包")
	}
	return &wallet, nil
}

// 支付宝异步
func AliAPayNotify(in *user.ALiPayNotifyReq) (*model.VirtualGoodsOrder, error) {
	order := &model.VirtualGoodsOrder{
		OrderSn: in.OrderSn,
		Status:  uint(in.OrderStatus),
	}
	if err := order.GetOrderSn(&model.VirtualGoodsOrder{OrderSn: in.OrderSn}); err != nil {
		return nil, fmt.Errorf("获取订单信息失败")
	}
	if order.Id == 0 {
		return nil, fmt.Errorf("该订单不存在")
	}
	if err := order.UpdateOrder(&model.VirtualGoodsOrder{OrderSn: in.OrderSn}); err != nil {
		return nil, fmt.Errorf("更新订单状态失败")
	}
	return order, nil
}

// 支付宝同步
func AliPayReturn(in *user.ALiPayReturnReq) (*model.VirtualGoodsOrder, error) {
	var order model.VirtualGoodsOrder
	if err := order.GetOrderSn(&model.VirtualGoodsOrder{OrderSn: in.OrderSn}); err != nil {
		return nil, fmt.Errorf("获取订单信息失败")
	}
	return &order, nil
}

// 获取用户背包列表
func GetUserInventory(in *user.GetUserInventoryReq) (*user.GetUserInventoryResp, error) {
	var inventory model.UserInventory

	// 获取背包列表
	details, err := inventory.GetUserInventoryList(uint(in.UserId), int(in.Page), int(in.PageSize), int(in.GoodsType))
	if err != nil {
		return nil, fmt.Errorf("获取背包列表失败: %v", err)
	}

	// 获取总数量
	total, err := inventory.GetUserInventoryCount(uint(in.UserId), int(in.GoodsType))
	if err != nil {
		return nil, fmt.Errorf("获取背包总数失败: %v", err)
	}

	// 计算总页数
	totalPage := (total + int64(in.PageSize) - 1) / int64(in.PageSize)
	if totalPage < 1 {
		totalPage = 1
	}

	// 构建返回列表
	list := buildInventoryItemList(details)

	return &user.GetUserInventoryResp{
		List:      list,
		Total:     total,
		Page:      int32(in.Page),
		PageSize:  int32(in.PageSize),
		TotalPage: int32(totalPage),
	}, nil
}

// 构建背包项列表
func buildInventoryItemList(details []model.UserInventoryDetail) []*user.InventoryItem {
	var list []*user.InventoryItem

	for _, detail := range details {
		item := &user.InventoryItem{
			InventoryId:  int64(detail.Id),
			GoodsId:      int64(detail.GoodsId),
			GoodsName:    detail.GoodsName,
			ImageUrl:     detail.ImageUrl,
			GoodsType:    int64(detail.GoodsType),
			Quantity:     int64(detail.Quantity),
			Status:       int64(detail.Status),
			ObtainTime:   detail.CreateTime.Format("2006-01-02 15:04:05"),
			EffectConfig: detail.EffectConfig,
			Description:  detail.Description,
		}

		// 处理过期时间
		if !detail.ExpireTime.IsZero() {
			item.ExpireTime = detail.ExpireTime.Format("2006-01-02 15:04:05")
		}

		list = append(list, item)
	}

	return list
}
